/**
* @File:w25qxx.c
* @Version:V1.0
* @Author:rudius
* @Brief: SPI Flash W25QXX Driver Implementation
* @Logs:
* 	Date		Author		Notes
* 	2025-06-19	rudius		First version
*/

// <<< Use Configuration Wizard in Context Menu >>>

/* Private includes --------------------------------------------------------- */
#include "w25qxx.h"
#include "drv_spi.h"   // 用户SPI驱动
#include <rtthread.h>
#include <string.h>
#include <rtdef.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Private config ----------------------------------------------------------- */
#define W25QXX_DEFAULT_TIMEOUT    5000  // 默认操作超时(ms)
#define W25QXX_SECTOR_SIZE         4096  // 扇区大小(4KB)
#define W25QXX_PAGE_SIZE           256   // 页大小(256B)

/* Private defines ---------------------------------------------------------- */
/* 状态寄存器位掩码 */
#define STATUS1_BUSY_MASK         0x01
#define STATUS1_WEL_MASK          0x02
#define STATUS2_QE_MASK           0x02

/* Private typedef ---------------------------------------------------------- */
/* SPI传输消息结构 */
typedef struct {
    uint8_t command;
    uint8_t address[3];
    uint8_t dummy;
    uint8_t data[];
} spi_transfer_msg_t;

/* Private variables -------------------------------------------------------- */
static uint8_t s_dummy_buffer[16]; // 用于虚拟传输的缓冲区
static rt_slist_t s_device_list;    // 设备列表
static rt_mutex_t s_device_list_lock; // 设备列表锁
static const w25qxx_config_t s_default_config = {
    .spi_bus = RT_NULL,
    .cs_pin = -1,
    .quad_mode = false,
    .capacity = 0,
    .sector_count = 0,
    .page_size = W25QXX_PAGE_SIZE,
    .max_clock_speed = 10000000 // 默认10MHz
};
/* Private function prototypes ---------------------------------------------- */
static int spi_transfer(w25qxx_device_t *dev, const uint8_t *tx_buf, 
                        uint8_t *rx_buf, size_t len);
static int wait_busy(w25qxx_device_t *dev, uint32_t timeout_ms);
static int send_command(w25qxx_device_t *dev, uint8_t command);
static int send_command_with_address(w25qxx_device_t *dev, uint8_t command, 
                                    uint32_t address);
static int read_data(w25qxx_device_t *dev, uint32_t addr, uint8_t *data, 
                    size_t len, uint8_t read_cmd);
static int w25qxx_module_init(void);
/*----------------------------------------------------------------------------*/
/* Private functions -------------------------------------------------------- */

/**
 * @brief SPI传输封装函数
 * @param dev 设备句柄
 * @param tx_buf 发送缓冲区
 * @param rx_buf 接收缓冲区
 * @param len 传输长度
 * @return 错误代码
 */
static int spi_transfer(w25qxx_device_t *dev, const uint8_t *tx_buf, 
                       uint8_t *rx_buf, size_t len)
{
    struct rt_spi_message msg;
    struct rt_spi_device *spi_dev = (struct rt_spi_device *)dev->config.spi_bus;
    
    // 初始化消息结构
    msg.send_buf = tx_buf;
    msg.recv_buf = rx_buf;
    msg.length = len;
    msg.cs_take = 1;      // 传输开始前拉低CS
    msg.cs_release = 1;   // 传输结束后拉高CS
    msg.next = NULL;      // 单次传输，无下一个消息
    
    // 获取SPI总线控制权
    if (rt_spi_take_bus(spi_dev) != RT_EOK) {
        return W25QXX_ERR_NOT_FOUND;
    }
    
    // 执行SPI传输
    rt_err_t ret = rt_spi_transfer(spi_dev, &msg.send_buf,&msg.recv_buf,msg.length);
    
    // 释放SPI总线控制权
    rt_spi_release_bus(spi_dev);
    
    return (ret == RT_EOK) ? W25QXX_OK : W25QXX_ERR_WRITE;
}

/**
 * @brief 发送命令（无数据）
 * @param dev 设备句柄
 * @param command 命令字节
 * @return 错误代码
 */
static int send_command(w25qxx_device_t *dev, uint8_t command)
{
    return spi_transfer(dev, &command, NULL, 1);
}

/**
 * @brief 发送带地址的命令
 * @param dev 设备句柄
 * @param command 命令字节
 * @param address 24位地址
 * @return 错误代码
 */
static int send_command_with_address(w25qxx_device_t *dev, uint8_t command, 
                                    uint32_t address)
{
    uint8_t tx_buf[4];
    
    tx_buf[0] = command;
    tx_buf[1] = (address >> 16) & 0xFF; // A23-A16
    tx_buf[2] = (address >> 8)  & 0xFF; // A15-A8
    tx_buf[3] = address & 0xFF;        // A7-A0
    
    return spi_transfer(dev, tx_buf, NULL, 4);
}

/**
 * @brief 等待设备完成内部操作
 * @param dev 设备句柄
 * @param timeout_ms 超时时间(ms)
 * @return 错误代码
 */
static int wait_busy(w25qxx_device_t *dev, uint32_t timeout_ms)
{
    uint8_t status;
    rt_tick_t start_tick = rt_tick_get();
    rt_tick_t timeout_tick = rt_tick_from_millisecond(timeout_ms);
    
    do {
        // 读取状态寄存器1
        int ret = w25qxx_read_status(dev, 1, &status);
        if (ret != W25QXX_OK) {
            return ret;
        }
        
        // 检查BUSY位
        if (!(status & STATUS1_BUSY_MASK)) {
            return W25QXX_OK;
        }
        
        rt_thread_mdelay(1);
    } while (rt_tick_get() - start_tick < timeout_tick);
    
    return W25QXX_ERR_TIMEOUT;
}

/**
 * @brief 读取数据通用函数
 * @param dev 设备句柄
 * @param addr 起始地址
 * @param data 数据缓冲区
 * @param len 数据长度
 * @param read_cmd 读取命令
 * @return 错误代码
 */
static int read_data(w25qxx_device_t *dev, uint32_t addr, uint8_t *data, 
                    size_t len, uint8_t read_cmd)
{
    // 检查参数有效性
    if (addr + len > dev->config.capacity) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 构造传输消息
    spi_transfer_msg_t *msg = rt_malloc(sizeof(spi_transfer_msg_t) + len);
    if (!msg) {
        return W25QXX_ERR_MEMORY;
    }
    
    // 设置命令和地址
    msg->command = read_cmd;
    msg->address[0] = (addr >> 16) & 0xFF; // A23-A16
    msg->address[1] = (addr >> 8)  & 0xFF; // A15-A8
    msg->address[2] = addr & 0xFF;        // A7-A0
    
    // 设置虚拟字节（根据不同命令）
    if (read_cmd == W25QXX_CMD_FAST_READ || 
        read_cmd == W25QXX_CMD_FAST_READ_DUAL || 
        read_cmd == W25QXX_CMD_FAST_READ_QUAD) {
        msg->dummy = 0xFF; // 快速读取需要1个虚拟字节
    } else {
        msg->dummy = 0;    // 标准读取不需要虚拟字节
    }
    
    // 执行SPI传输
    int ret = spi_transfer(dev, (uint8_t *)msg, data, sizeof(spi_transfer_msg_t) + len - 1);
    
    rt_free(msg);
    return ret;
}

/* 设备管理接口实现 --------------------------------------------------------- */

/**
 * @brief 创建并注册W25QXX设备
 * @param name 设备名称
 * @param config 设备配置
 * @return 设备句柄指针，失败返回NULL
 */
w25qxx_device_t *w25qxx_create(const char *name, const w25qxx_config_t *config)
{
    if (!name || !config || !config->spi_bus) {
        return NULL;
    }
    
    // 检查设备是否已存在
    if (w25qxx_find(name) != NULL) {
        return NULL;
    }
    
    // 分配设备内存
    w25qxx_device_t *dev = rt_malloc(sizeof(w25qxx_device_t));
    if (!dev) {
        return NULL;
    }
    
    // 初始化设备
    rt_memset(dev, 0, sizeof(w25qxx_device_t));
    dev->name = name;
    dev->config = *config;
    
    // 初始化互斥锁
    if (rt_mutex_init(dev->lock, name, RT_IPC_FLAG_FIFO) != RT_EOK) {
        rt_free(dev);
        return NULL;
    }
    
    // 初始化设备
    if (w25qxx_init_device(dev) != W25QXX_OK) {
        rt_mutex_detach(dev->lock);
        rt_free(dev);
        return NULL;
    }
    

    
    return dev;
}

/**
 * @brief 销毁并注销W25QXX设备
 * @param dev 设备句柄
 */
void w25qxx_destroy(w25qxx_device_t *dev)
{
    if (!dev) return;
    
    // 从设备列表中移除
    rt_mutex_take(s_device_list_lock, RT_WAITING_FOREVER);
    rt_slist_remove(&s_device_list, &dev->list);
    rt_mutex_release(s_device_list_lock);
    
    // 释放资源
    rt_mutex_detach(dev->lock);
    rt_free(dev);
}

/**
 * @brief 通过名称查找W25QXX设备
 * @param name 设备名称
 * @return 设备句柄指针，未找到返回NULL
 */
w25qxx_device_t *w25qxx_find(const char *name)
{
    if (!name) return NULL;
    
    rt_mutex_take(s_device_list_lock, RT_WAITING_FOREVER);
    
    rt_slist_t *node;
    rt_slist_for_each(node, &s_device_list)
    {
        w25qxx_device_t *dev = rt_slist_entry(node, w25qxx_device_t, list);
        if (rt_strcmp(dev->name, name) == 0) {
            rt_mutex_release(s_device_list_lock);
            return dev;
        }
    }
    
    rt_mutex_release(s_device_list_lock);
    return NULL;
}

/* 设备操作接口实现 --------------------------------------------------------- */

/**
 * @brief 初始化W25QXX设备
 * @param dev 设备句柄指针
 * @return int 错误代码 (W25QXX_OK 表示成功)
 */
int w25qxx_init_device(w25qxx_device_t *dev)
{
    if (!dev || !dev->config.spi_bus) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 初始化状态寄存器缓存
    dev->status_reg1 = 0;
    dev->status_reg2 = 0;
    
    // 读取设备ID验证通信
    uint8_t mfg_id;
    uint16_t dev_id;
    int ret = w25qxx_read_id(dev, &mfg_id, &dev_id);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 验证制造商ID (Winbond: 0xEF)
    if (mfg_id != 0xEF) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 读取状态寄存器
    ret = w25qxx_read_status(dev, 1, &dev->status_reg1);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    ret = w25qxx_read_status(dev, 2, &dev->status_reg2);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 如果需要Quad模式但未启用，则启用它
    if (dev->config.quad_mode && !(dev->status_reg2 & STATUS2_QE_MASK)) {
        uint8_t new_status = dev->status_reg2 | STATUS2_QE_MASK;
        ret = w25qxx_write_enable(dev);
        if (ret != W25QXX_OK) {
            return ret;
        }
        
        uint8_t tx_buf[2] = {W25QXX_CMD_WRITE_STATUS_REG, new_status};
        ret = spi_transfer(dev, tx_buf, NULL, 2);
        if (ret != W25QXX_OK) {
            return ret;
        }
        
        ret = wait_busy(dev, W25QXX_DEFAULT_TIMEOUT);
        if (ret != W25QXX_OK) {
            return ret;
        }
        
        dev->status_reg2 = new_status;
    }
    
        // 添加到设备列表
    rt_mutex_take(s_device_list_lock, RT_WAITING_FOREVER);
    rt_slist_append(&s_device_list, &dev->list);
    rt_mutex_release(s_device_list_lock);

    return W25QXX_OK;
}

int w25qxx_read_id(w25qxx_device_t *dev, uint8_t *manufacturer_id, uint16_t *device_id)
{
    if (!dev || !manufacturer_id || !device_id) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    uint8_t tx_buf[1] = {W25QXX_CMD_READ_JEDEC_ID};
    uint8_t rx_buf[3] = {0};
    
    // 执行SPI传输
    int ret = spi_transfer(dev, tx_buf, rx_buf, sizeof(rx_buf));
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    *manufacturer_id = rx_buf[0];
    *device_id = (rx_buf[1] << 8) | rx_buf[2];
    
    return W25QXX_OK;
}

int w25qxx_read_status(w25qxx_device_t *dev, uint8_t reg_num, uint8_t *status)
{
    if (!dev || !status || reg_num < 1 || reg_num > 3) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    uint8_t command;
    switch (reg_num) {
        case 1: command = W25QXX_CMD_READ_STATUS_REG1; break;
        case 2: command = W25QXX_CMD_READ_STATUS_REG2; break;
        case 3: command = W25QXX_CMD_READ_STATUS_REG3; break;
        default: return W25QXX_ERR_INVALID_ARG;
    }
    
    uint8_t tx_buf[1] = {command};
    uint8_t rx_buf[2] = {0}; // 命令字节 + 状态字节
    
    // 执行SPI传输
    int ret = spi_transfer(dev, tx_buf, rx_buf, 2);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    *status = rx_buf[1];
    
    // 更新缓存
    if (reg_num == 1) dev->status_reg1 = *status;
    else if (reg_num == 2) dev->status_reg2 = *status;
    
    return W25QXX_OK;
}

int w25qxx_write_enable(w25qxx_device_t *dev)
{
    if (!dev) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    int ret = send_command(dev, W25QXX_CMD_WRITE_ENABLE);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 验证WEL位是否置位
    uint8_t status;
    ret = w25qxx_read_status(dev, 1, &status);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    if (!(status & STATUS1_WEL_MASK)) {
        return W25QXX_ERR_WRITE;
    }
    
    return W25QXX_OK;
}

int w25qxx_write_disable(w25qxx_device_t *dev)
{
    if (!dev) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    return send_command(dev, W25QXX_CMD_WRITE_DISABLE);
}

int w25qxx_wait_busy(w25qxx_device_t *dev, uint32_t timeout_ms)
{
    return wait_busy(dev, timeout_ms);
}

int w25qxx_erase_sector(w25qxx_device_t *dev, uint32_t sector_addr)
{
    if (!dev) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 计算物理地址
    uint32_t addr = sector_addr * W25QXX_SECTOR_SIZE;
    if (addr >= dev->config.capacity) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 写使能
    int ret = w25qxx_write_enable(dev);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 发送扇区擦除命令
    ret = send_command_with_address(dev, W25QXX_CMD_SECTOR_ERASE, addr);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 等待操作完成
    return wait_busy(dev, W25QXX_DEFAULT_TIMEOUT);
}

int w25qxx_erase_block_32k(w25qxx_device_t *dev, uint32_t block_addr)
{
    if (!dev) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 计算物理地址
    uint32_t addr = block_addr * 32768;
    if (addr >= dev->config.capacity) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 写使能
    int ret = w25qxx_write_enable(dev);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 发送32K块擦除命令
    ret = send_command_with_address(dev, W25QXX_CMD_BLOCK_ERASE_32K, addr);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 等待操作完成
    return wait_busy(dev, W25QXX_DEFAULT_TIMEOUT);
}

int w25qxx_erase_block_64k(w25qxx_device_t *dev, uint32_t block_addr)
{
    if (!dev) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 计算物理地址
    uint32_t addr = block_addr * 65536;
    if (addr >= dev->config.capacity) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 写使能
    int ret = w25qxx_write_enable(dev);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 发送64K块擦除命令
    ret = send_command_with_address(dev, W25QXX_CMD_BLOCK_ERASE_64K, addr);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 等待操作完成
    return wait_busy(dev, W25QXX_DEFAULT_TIMEOUT);
}

int w25qxx_erase_chip(w25qxx_device_t *dev)
{
    if (!dev) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 写使能
    int ret = w25qxx_write_enable(dev);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 发送整片擦除命令
    ret = send_command(dev, W25QXX_CMD_CHIP_ERASE);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 等待操作完成
    return wait_busy(dev, 10000); // 整片擦除需要更长时间
}

int w25qxx_page_program(w25qxx_device_t *dev, uint32_t addr, const uint8_t *data, size_t len)
{
    if (!dev || !data || len == 0) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 检查地址和长度是否有效
    if (addr >= dev->config.capacity || 
        addr + len > dev->config.capacity ||
        len > W25QXX_PAGE_SIZE) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 检查是否页对齐
    if ((addr % W25QXX_PAGE_SIZE) + len > W25QXX_PAGE_SIZE) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 写使能
    int ret = w25qxx_write_enable(dev);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 构造传输消息
    spi_transfer_msg_t *msg = rt_malloc(sizeof(spi_transfer_msg_t) + len);
    if (!msg) {
        return W25QXX_ERR_MEMORY;
    }
    
    // 设置命令和地址
    msg->command = W25QXX_CMD_PAGE_PROGRAM;
    msg->address[0] = (addr >> 16) & 0xFF;
    msg->address[1] = (addr >> 8)  & 0xFF;
    msg->address[2] = addr & 0xFF;
    
    // 复制数据
    memcpy(msg->data, data, len);
    
    // 执行SPI传输
    ret = spi_transfer(dev, (uint8_t *)msg, NULL, sizeof(spi_transfer_msg_t) + len - 1);
    
    rt_free(msg);
    
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 等待操作完成
    return wait_busy(dev, W25QXX_DEFAULT_TIMEOUT);
}

int w25qxx_quad_page_program(w25qxx_device_t *dev, uint32_t addr, const uint8_t *data, size_t len)
{
    if (!dev || !data || len == 0) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 检查是否启用Quad模式
    if (!dev->config.quad_mode) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 检查地址和长度是否有效
    if (addr >= dev->config.capacity || 
        addr + len > dev->config.capacity ||
        len > W25QXX_PAGE_SIZE) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 检查是否页对齐
    if ((addr % W25QXX_PAGE_SIZE) + len > W25QXX_PAGE_SIZE) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 写使能
    int ret = w25qxx_write_enable(dev);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 构造传输消息
    spi_transfer_msg_t *msg = rt_malloc(sizeof(spi_transfer_msg_t) + len);
    if (!msg) {
        return W25QXX_ERR_MEMORY;
    }
    
    // 设置命令和地址
    msg->command = W25QXX_CMD_QUAD_PAGE_PROGRAM;
    msg->address[0] = (addr >> 16) & 0xFF;
    msg->address[1] = (addr >> 8)  & 0xFF;
    msg->address[2] = addr & 0xFF;
    
    // 复制数据
    memcpy(msg->data, data, len);
    
    // 执行SPI传输
    ret = spi_transfer(dev, (uint8_t *)msg, NULL, sizeof(spi_transfer_msg_t) + len - 1);
    
    rt_free(msg);
    
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 等待操作完成
    return wait_busy(dev, W25QXX_DEFAULT_TIMEOUT);
}

int w25qxx_read_data(w25qxx_device_t *dev, uint32_t addr, uint8_t *data, size_t len)
{
    return read_data(dev, addr, data, len, W25QXX_CMD_READ_DATA);
}

int w25qxx_fast_read(w25qxx_device_t *dev, uint32_t addr, uint8_t *data, size_t len)
{
    return read_data(dev, addr, data, len, W25QXX_CMD_FAST_READ);
}

int w25qxx_quad_read(w25qxx_device_t *dev, uint32_t addr, uint8_t *data, size_t len)
{
    // 检查是否启用Quad模式
    if (!dev->config.quad_mode) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    return read_data(dev, addr, data, len, W25QXX_CMD_FAST_READ_QUAD);
}

int w25qxx_reset(w25qxx_device_t *dev)
{
    if (!dev) {
        return W25QXX_ERR_INVALID_ARG;
    }
    
    // 发送使能复位命令
    int ret = send_command(dev, W25QXX_CMD_ENABLE_RESET);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 发送复位命令
    ret = send_command(dev, W25QXX_CMD_RESET_DEVICE);
    if (ret != W25QXX_OK) {
        return ret;
    }
    
    // 等待复位完成
    rt_thread_mdelay(30); // 复位需要约30ms
    
    return W25QXX_OK;
}

/* 模块初始化函数 */
static int w25qxx_module_init(void)
{
    // 初始化设备列表
    rt_slist_init(&s_device_list);
    
    // 初始化设备列表锁
    s_device_list_lock = rt_mutex_create("w25qxx_list_lock", RT_IPC_FLAG_FIFO);
    if (s_device_list_lock == RT_NULL) {
        return W25QXX_ERR_NOT_FOUND;
    }
    rt_kprintf("W25QXX module initialized\n");
    return RT_EOK;
}
INIT_APP_EXPORT(w25qxx_module_init);


#ifdef __cplusplus
}
#endif
// <<< end of configuration section >>>
/* ----------------------------- end of w25qxx.c ---------------------------- */